#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pseudo_fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/namei.h>
#include <linux/nsproxy.h>
#include "../mount.h"

extern struct task_struct init_task;

// yafs
#define MYFS_MAGIC 0x79616673

static struct dentry *myfs_mount(struct file_system_type *fs_type,
				 int flags, const char *dev_name,
				 void *data);

static void myfs_kill_sb(struct super_block *sb)
{
	kill_litter_super(sb);
	pr_info("myfs: superblock destroyed\n");
}

static struct file_system_type myfs_type = {
	.owner = THIS_MODULE,
	.name = "aayafs",
	.mount = myfs_mount,
	.kill_sb = myfs_kill_sb,
	.fs_flags = FS_USERNS_MOUNT,
};

static const struct super_operations myfs_super_ops = {

};

static int myfs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct inode *inode;
	struct dentry *root;

	sb->s_magic = MYFS_MAGIC;
	sb->s_op = &myfs_super_ops;

	inode = new_inode(sb);
	if (!inode)
		return -ENOMEM;

	inode->i_ino = 1;
	inode->i_sb = sb;
	inode->i_op = &simple_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;
	inode->i_mode = S_IFDIR | 0755;
	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);

	root = d_make_root(inode);
	if (!root)
		return -ENOMEM;

	sb->s_root = root;
	return 0;
}

static struct dentry *myfs_mount(struct file_system_type *fs_type,
				 int flags, const char *dev_name,
				 void *data)
{
	return mount_nodev(fs_type, flags, data, myfs_fill_super);
}

static int __init myfs_init(void)
{
	struct mount* mnt;
	struct mnt_namespace* mnt_ns = init_task.nsproxy->mnt_ns;
	list_for_each_entry(mnt, &mnt_ns->list, mnt_list) {
		printk("Mount point: %s\n", mnt->mnt_mountpoint->d_name.name);
	}

	// 上面的宏展开
	{
		struct list_head *__pos;

		for (__pos = (mnt_ns->list).next;
		     __pos != &(mnt_ns->list);
		     __pos = __pos->next) {

			mnt = list_entry(__pos, struct mount, mnt_list);

			printk("Mount point: %s\n", mnt->mnt_mountpoint->d_name.name);
		}
	}

	pr_info("myfs: init\n");
	return register_filesystem(&myfs_type);
}

static void __exit myfs_exit(void)
{
	unregister_filesystem(&myfs_type);
	pr_info("myfs: exit\n");
}

module_init(myfs_init);
module_exit(myfs_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ziya");
MODULE_DESCRIPTION("Minimal nodev fs with custom fill_super");
